package org.jjj.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.jjj.basic.constants.WxConstants;
import org.jjj.basic.utils.HttpClientUtils;
import org.jjj.basic.utils.MD5Utils;
import org.jjj.basic.utils.ResultAjax;
import org.jjj.user.domain.Logininfo;
import org.jjj.user.domain.Wxuser;
import org.jjj.user.dto.LoginDTO;
import org.jjj.user.dto.PhoneSmsLoginDTO;
import org.jjj.user.mapper.LogininfoMapper;
import org.jjj.user.mapper.WxuserMapper;
import org.jjj.user.service.ILogininfoService;
import org.jjj.basic.service.impl.BaseServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author jiangjianjun
 * @since 2022-11-14
 */
@Service
public class LogininfoServiceImpl extends BaseServiceImpl<Logininfo> implements ILogininfoService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxuserMapper wxuserMapper;

    /**
     * 门户网站和后端管理平台登录用一个接口
     * @param dto
     * @return
     */
    @Override
    public ResultAjax loginAccount(LoginDTO dto) {
        String account = dto.getAccount();
        String password = dto.getPassword();
        Integer type = dto.getType();
        //1.前端参数非空校验
        if (StringUtils.isEmpty(account)||
            StringUtils.isEmpty(password)||type==null){
            return ResultAjax.me().setSuccess(false).setMessage("请填写完整登录信息后再登录！");
        }
        //2.判断账号是否正确
        //根据账号先去数据库中查询用户信息
        Logininfo logininfo = logininfoMapper.getLogininfoByAccount(dto);
        if (logininfo==null){
            return ResultAjax.me().setSuccess(false).setMessage("账号或密码错误,请检查后重新登录！");
        }
        //3.判断用户状态
        if (logininfo.getDisable()==0){
            return ResultAjax.me().setSuccess(false).setMessage("次账号已被冻结，请联系客服！");
        }
        //4.判断密码是否正确，这里需要对传进来的密码进行加盐加密处理才能比对
        String salt = logininfo.getSalt();
        String passwordOfDB = logininfo.getPassword();
        String encrypByMd5 = MD5Utils.encrypByMd5("123" + salt + "jjj" + password);
        if (!encrypByMd5.equals(passwordOfDB)){
            return ResultAjax.me().setSuccess(false).setMessage("账号或密码错误,请检查后重新登录！");
        }
        //5.登录成功方法
        return handleLoginSuccess(logininfo);
    }

    /**
     * 微信登录接口
     * 用户扫微信码登录，这里的主要业务是判断一下这个微信用户在自己平台的t_wxuser表中是否存在
     * 1.存在就直接免密登录
     * 2.不存在就跳转到绑定页面去绑定这个微信用户，也就是将这个微信用户最终存入自己的数据库
     * 我们注册用户用的是手机号注册，所以绑定需要手机号去绑定
     * @param codeMap
     * @return
     */
    @Override
    public ResultAjax wechatLogin(Map<String, Object> codeMap) {
        //1.根据用户授权成功微信返回来的code再去微信平台获取accessToken和openid
        String code = codeMap.get("code").toString();
        String accessUrl = WxConstants.GET_ACK_URL
                .replace("APPID", WxConstants.APPID)
                .replace("SECRET", WxConstants.SECRET)
                .replace("CODE", code);
        //向微信平台发送请求获取accessToken和openid
        String accessStr = HttpClientUtils.httpGet(accessUrl);
        //将返回来的字符串转成对象
        JSONObject accessObject = JSONObject.parseObject(accessStr);
        String accessToken = accessObject.getString("access_token");
        String openid = accessObject.getString("openid");
        //2.根据openid去数据库查询看当前微信登录用户是否已经存在
        Wxuser wxuser = wxuserMapper.selectByOpenId(openid);
        if (Objects.nonNull(wxuser)){
            //2.1如果存在，直接免密登录
            //2.1.1先去数据库查询logininfo,因为登录成功后需要将token和logininfo返回给前端
            Logininfo logininfo = logininfoMapper.getLogininfoByUserId(wxuser.getUserId());
            return handleLoginSuccess(logininfo);
        }else {
            //2.2如果不存在，说明还没有绑定过，就告诉前端需要跳转到绑定页面去绑定这个用户到自己的数据库
            //这里需要将accessToken和openid传递到前端，后面做绑定需要用到
            HashMap<String, Object> map = new HashMap<>();
            map.put("openid",openid);
            map.put("accessToken",accessToken);
            return ResultAjax.me().setSuccess(false).setMessage("toBind").setResult(map);
        }
    }

    /**
     * 手机验证码登录
     * @param dto
     * @return
     */
    @Override
    public ResultAjax phoneSmsCodeLogin(PhoneSmsLoginDTO dto) {
        String phone = dto.getMobile();
        String smsCode = dto.getSmsCode();
        Integer type = dto.getType();
        //1.前端参数非空校验
        if (StringUtils.isEmpty(phone)||
                StringUtils.isEmpty(smsCode)||type==null){
            return ResultAjax.me().setSuccess(false).setMessage("请填写完整登录信息后再登录！");
        }
        //2.输入的手机验证码是否正确
        String key = "phone_sms_code_"+phone;//存入redis中数据的key
        //从redis中取出之前存入的手机短信验证码
        String smsCodeOfRedis = (String)redisTemplate.opsForValue().get(key);
        String phoneCode = smsCodeOfRedis.split(":")[0];
        if (StringUtils.isEmpty(smsCodeOfRedis)){
            return ResultAjax.me().setSuccess(false).setMessage("手机短信验证码已过期,请重新获取！");
        }
        if (!smsCode.equals(phoneCode)){
            return ResultAjax.me().setSuccess(false).setMessage("手机验证码输入错误！");
        }
        //3.判断账号是否存在
        //根据账号先去数据库中查询用户信息
        Logininfo logininfo = logininfoMapper.getLogininfoByPhone(dto);
        if (logininfo==null){
            return ResultAjax.me().setSuccess(false).setMessage("用户还没注册，请先去注册！");
        }
        //3.判断用户状态
        if (logininfo.getDisable()==0){
            return ResultAjax.me().setSuccess(false).setMessage("此账号已被冻结，请联系客服！");
        }
        //4.登录成功方法
        return handleLoginSuccess(logininfo);
    }
    /**
     * 免密登录方法
     * @param logininfo
     * @return
     */
    private ResultAjax handleLoginSuccess(Logininfo logininfo){
        //5.记录logininfo到redis中，后面登录拦截功能要来检查里面的数据，看用户是否已经登录
        //key为token
        String token = UUID.randomUUID().toString();
        //存入redis中，过期时间为30分钟·
        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
        //6.登录成功返回token后续请求资源时需要携带着token来查看用户是否已经登录,和logininfo前端页面展示当前登录用户
        HashMap<String, Object> map = new HashMap<>();
        map.put("token",token);
        //再将信息返回前端之前需要将密码和盐值置空，以防信息泄露
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("logininfo",logininfo);
        return ResultAjax.me().setResult(map);
    }
}
